package com.ruoyi.video.server.ws;

import com.ruoyi.common.utils.ExceptionUtil;
import com.ruoyi.video.domain.VideoCamera;
import com.ruoyi.video.server.utils.RtspThread;
import com.ruoyi.video.service.IVideoCameraService;
import com.ruoyi.video.server.ws.config.WebSocketSessionConfigurator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

@ServerEndpoint(value = "/rtsp/{cameraId}/real.flv", configurator = WebSocketSessionConfigurator.class)
@Component
@Slf4j
public class RtspWebSocket {
    /** 静态变量 */
    private final static ConcurrentHashMap<String, Set<Session>> clientMap = new ConcurrentHashMap<>();
    private final static ConcurrentHashMap<String, RtspThread> threadMap = new ConcurrentHashMap<>();
    private final static ConcurrentHashMap<Session, String> sessionMap = new ConcurrentHashMap<>();

    private static IVideoCameraService videoCameraService;

    @Autowired
    public void setVideoCameraService(IVideoCameraService videoCameraService){
        this.videoCameraService = videoCameraService;
    }

    /**
     * On open.
     *
     * @param session the session
     * @param cameraId  the 设备ID
     */
    @OnOpen
    public void onOpen(Session session, EndpointConfig config,
                       @PathParam("cameraId") Long cameraId) {
        try {
            VideoCamera videoCamera = videoCameraService.selectVideoCameraById(cameraId);
            String rtsp = videoCamera.getRtsp();// "rtsp://admin:zhian12345@192.168.2.163:554/Streaming/Channels/101?transportmode=unicast&profile=Profile_1";

            Set<Session> sets = clientMap.get(rtsp);
            if(sets == null){
                sets = new HashSet<>();
                sets.add(session);
                clientMap.put(rtsp, sets);
            }else{
                sets.add(session);
            }
            sessionMap.put(session, rtsp);
            RtspThread thread = threadMap.get(rtsp);
            if(thread == null){
                thread = new RtspThread(rtsp);
                thread.start();
                threadMap.put(rtsp, thread);
            }else{
                if(thread.getHeaders() != null){
                    session.getBasicRemote().sendBinary(ByteBuffer.wrap(thread.getHeaders()));
                }
            }

            log.info("摄像机{}有新的播放请求！当前在线{}个", rtsp, clientMap.size());
        } catch (Exception e) {
            e.printStackTrace();
            log.error("websocket IO异常");
        }
    }

    /**
     * On close.
     *
     * @param session the session
     * @throws IOException the io exception
     */
    @OnClose
    public void onClose(Session session) throws IOException {
        String rtsp = sessionMap.remove(session);
        if(rtsp == null){
            return;
        }
        Set<Session> sets = clientMap.get(rtsp);
        if(!sets.isEmpty()){
            sets.remove(session);
        }
        if(sets.isEmpty()){
            RtspThread thread = threadMap.get(rtsp);
            if(thread != null) {
                thread.setRuning(false);
                threadMap.remove(rtsp);
            }
            log.info("摄像机{}的播放连接全部断开,将停止拉流！",rtsp);
        }else{
            log.info("摄像机{}的播放连接已断开,当前在线{}个！", rtsp, sets.size());
        }
    }

    /**
     * On error.
     *
     * @param session the session
     * @param t       the t
     */
    @OnError
    public void onError(Session session, Throwable t) {
        try {
            if (!session.isOpen()) {
                log.error("session 连接发生异常,主动关闭连接!,异常信息:{}", ExceptionUtil.getExceptionMessage(t));
                this.onClose(session);
            } else {
                log.error("Ws error occurred , msg : {}", ExceptionUtil.getExceptionMessage(t));
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("Failed to close ws connection , msg :{}", ExceptionUtil.getExceptionMessage(e));
        }
    }

    /**
     * On message.
     *
     * @param session the session
     * @param message the message
     */
    @OnMessage
    public void onMessage(Session session, String message) {
        log.info("receive dahua player msg: {}", message);
    }

    /**
     * 向播放器发送消息
     * @param rtsp
     * @param bytes
     */
    public static void sendData(String rtsp, byte[] bytes){
        // log.debug("向摄像机{}的播放器发送数据，{}个", deviceId, clientMap.get(deviceId).size());
        ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
        for(Session session: clientMap.get(rtsp)){
            try{
                if(session != null){
                    session.getBasicRemote().sendBinary(byteBuffer);
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }

    }
}
